package tileStyle;

import tileStyle.Prism.events.KeepAlive;
import Prism.core.AbstractImplementation;
import Prism.core.Brick;
import Prism.core.Component;
import Prism.core.Event;
import Prism.core.IPort;
import Prism.core.Port;
import Prism.core.PrismConstants;
import Prism.extensions.port.ExtensiblePort;

public abstract class TileStyleComponent extends Component {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	protected TileStyleComponent(String name) {
		super(name);
		
		launchKeepAlive();
	}

	protected TileStyleComponent(String name, AbstractImplementation implementation) {
		super(name, implementation);
		
		launchKeepAlive();
	}
	
	protected void launchKeepAlive() {
		keepAlive ka = new keepAlive(this, 10000);
		ka.start();
	}
	
	/*
	 * This method sends the event up/down the Prism architecture that this component is a
	 * part of.
	 *
	 * @param Event e : Event to be sent.
	 * @param Port destination : the Port to which to send e.
	 */   
	public void send(Event e, Port destination)	{
		if (TileStyleStarter.DEBUG)
			System.out.println(this + " is sending event of type " + e.getClass() + " to " + destination);
		e.originatingBrick = this;
		if (destination.getPortType() == e.eventType) {
			if (destination instanceof ExtensiblePort) {
				e.handlingBrick = (Brick) destination;
				add(e);
			}
			else if (destination instanceof Port) {
				IPort mutualPort = destination.getMutualPort();
				e.handlingBrick = mutualPort.getParentBrick();
				add(e);
			}                        
		}
	}
	
	/**
	 * Keep alive thread
	 * 
	 * @author Jae young Bang
	 */
	protected class keepAlive extends Thread {
		
		private Component 	parent;
		private int			delay_milliseconds;			
		
		public keepAlive (Component parent, int delay_milliseconds) {
			this.parent 			= parent;
			this.delay_milliseconds = delay_milliseconds;
		}
		
		public void run () {
			while(true) {
				sendPacket();
				waitForNextPacket();
			}
		}
		
		protected void waitForNextPacket () {
			try {
				Thread.sleep(delay_milliseconds);
			} catch (InterruptedException e) {
				// do nothing
			}
		}
		
		protected void sendPacket () {
			// Creates a Snapshot Event and sends it over
			Event evt = (Event) new KeepAlive("KeepAlive");
			evt.originatingBrick = parent;
			
			// send the KeepAlive event to all of its connections
			sendRequest(evt);
			sendReply(evt);
		}
		
		/**
		 * Adds REQEUST event type and sends it over
		 * 
		 * @param e					Outgoing Event
		 */
		public void sendRequest(Event e) {
			e.eventType = PrismConstants.REQUEST;
			send(e);
		}
		
		/**
		 * Adds REPLY event type and sends it over
		 * 
		 * @param e					Outgoing Event
		 */
		public void sendReply (Event e) {
			e.eventType = PrismConstants.REPLY;
			send(e);
		}
	}
}
